package pers.cz.controller;

import pers.cz.encrypt.DesUtil;
import pers.cz.ftp.SftpUtil;
import pers.cz.model.AutoHostsDel;
import pers.cz.pub.RespBean;
import pers.cz.service.HotSwapService;
import pers.cz.ssh.SshUtil;
import io.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import pers.cz.tools.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 热替换
 * @program: PostGirl-panent
 * @description: HotSweap
 * @author: Cheng Zhi
 * @create: 2021-11-28 16:31
 **/
@RestController
@Scope( "prototype" )
@Api(tags = "热替换")
@RequestMapping(path = "/api/hotSweapController")
public class HotSwapController {

    Logger log = LoggerFactory.getLogger(HotSwapController.class);

    @Autowired
    HotSwapService service;

    @Value("${ftp.workpath}")
    String workpath;

    @PostMapping(path = "/queryAllAutoHostDel")
    public List<AutoHostsDel> queryAllAutoHostDel() {

        return service.queryAllAutoHostsDel();
    }

    @PostMapping(path = "/deleteAutoHostDel")
    public RespBean deleteAutoHostDel(@RequestBody Map map) {

        Integer id = (Integer) map.get("id");
        Integer count = service.deleteHosts(id);

        return RespBean.ok("成功删除" + count + "条");
    }
    @PostMapping(path = "/addAutoHostsDel")
    public Integer addAutoHostsDel(@RequestBody Map map) {

        String hostName = (String) map.get("hostName");
        String ip = (String) map.get("ip");
        String userName = (String) map.get("userName");
        String password = (String) map.get("password");

        AutoHostsDel autoHostsDel = new AutoHostsDel();
        autoHostsDel.setHostName(hostName);
        autoHostsDel.setIp(ip);
        autoHostsDel.setUserName(userName);
        autoHostsDel.setPassword(DesUtil.encrypt(password)); // 保存密码要加密

        return  service.addHosts(autoHostsDel);
    }

    @PostMapping("/upload")
    public RespBean upload(@RequestParam("file") MultipartFile file, @RequestParam("ip") String ip, @RequestParam("userName") String userName, @RequestParam("password") String password) throws IOException {

        String newPassword = DesUtil.decode(password); // 密码要解密
        Integer ftpPort = 22;
        try {
            SftpUtil sftp = new SftpUtil(userName, newPassword, ip, ftpPort);
            sftp.login();
            sftp.upload("./"+workpath, file.getOriginalFilename(), file.getInputStream());
            // 上传tools.jar、上传agent.jar、上传
            sftp.logout();
        } catch (Exception e) {
            log.error("file upload fail!", e);
            return RespBean.error("文件上传目标服务器失败!");
        }

        return RespBean.ok("上传成功");
    }

    @PostMapping(path = "/execHotSweap")
    public RespBean execHotSweap(@RequestBody Map map) {

        String hostName = (String) map.get("hostName");
        String ip = (String) map.get("ip");
        String userName = (String) map.get("userName");
        String password = DesUtil.decode((String) map.get("password")); // 密码要解密
        String pid = (String) map.get("pid");
        Integer pidType = (Integer) map.get("pidType");
        Integer port = 22;
        String fileName = (String) map.get("fileName");

        SshUtil sshUtil = new SshUtil();
        boolean login = sshUtil.login(ip, port, userName, password);
        if (!login) {
            return RespBean.error("登录主机失败，请检查参数是否正确");
        }

        // 返回结果
        StringBuilder stringBuilder = new StringBuilder();
        try {

            if ("1".equals(pidType) || pidType == 1) {
                // 如果是1则是账管进程，需要先兜取进程编号
                String commind = "jps -v | grep " + pid + " | awk -F '  *' '{print $1}'";
                log.info("--即将执行的命令--:" + commind);
                pid = sshUtil.exec(commind).toString();
                log.info("--命令执行结果--:" + pid);

                if ("".equals(pid)) {
                    return RespBean.error("执行失败！请确认进程是否存在");
                }
            }
            /**
             * work_path=$1
             * pid=$2
             * file_name=$3
             * cd ~
             * user_work_path=`pwd`
             * real_path=${user_work_path}${work_path}
             * hotswap_command="java -Xbootclasspath/a:$real_path/tools.jar -jar $real_path/hotswap-jdk.jar $pid $real_path/$file_name"
             * $hotswap_command
             */
            String realPath = sshUtil.getRealWorkPath(workpath);
            realPath = realPath.replaceAll("\r|\n", "");
            String shell = "java -Xbootclasspath/a:" + realPath + "/tools.jar -jar " + realPath + "/hotswap-jdk.jar " + pid.replaceAll("\r|\n", "") + " " + realPath + "/" + fileName;
            log.info("--热替换命令--:" + shell);
            stringBuilder = sshUtil.exec(shell, login);
            sshUtil.logout();
            log.info("--热替换返回结果--:" + stringBuilder);
            String returnMsg = stringBuilder.toString();
            sshUtil.logout();
            if (returnMsg.contains("POST-GIRL-ERROR-1")) {
                return RespBean.error("执行失败，请检查后台脚本配置！");
            } else if (returnMsg.contains("POST-GIRL-ERROR-2")) {
                return RespBean.error("执行失败，请检查Class文件或者进程是否存在！");
            } else if (returnMsg.contains("POST-GIRL-ERROR-3")) {
                return RespBean.error("执行失败，请检查代理包是否存在！");
            } else if (returnMsg.contains("POST-GIRL-ERROR-4")) {
                return RespBean.error("执行失败，请检查是否新增或删除原有方法！");
            } else if (returnMsg.contains("POST-GIRL-SUCCESS")) {
                return RespBean.ok("热替换成功");
            }
        } catch (Exception e) {
            return RespBean.error("执行失败，请检查命令");
        }

        return RespBean.ok("热替结果不明确，请人工确认！");
    }
    /**
     * 替换文件
     * @return
     */
    @PostMapping(path = "/execReplaceFile")
    public RespBean execReplaceFile(@RequestBody Map map) {
        String ip = (String) map.get("ip");
        String userName = (String) map.get("userName");
        String password = DesUtil.decode((String) map.get("password")); // 密码要解密
        Integer port = 22;
        String fileName = (String) map.get("fileName");
        String jarPath = (String) map.get("jarPath"); // 这个路径时包含文件名称的路径，所以需要去除后面的xxx.xx



        SshUtil sshUtil = new SshUtil();
        boolean login = sshUtil.login(ip, port, userName, password);
        if (!login) {
            return RespBean.error("登录主机失败，请检查参数是否正确");
        }

        try {
            // 目前的路径中是带有.xxx后缀的，需要获取到真实的路径
            //jarPath = jarPath.replace(fileName, "");
            String realPath =  sshUtil.getRealWorkPath(workpath);
            realPath = realPath.replaceAll("\r|\n", "");
            String shell = "cd " + realPath + "; jef replace " + jarPath + " " + fileName;
            log.info("--replace File command is--:" + shell);
            sshUtil.exec(shell, login);
            sshUtil.logout();
        } catch (Exception e) {
            e.printStackTrace();
            return RespBean.error("替换失败，请检查文件路径");
        }

        return RespBean.ok("替换成功");
    }

    /**
     * 获取所有的文件路径
     * @return
     */
    @PostMapping(path = "/getAllFilePath")
    public List<String> getAllFilePath(@RequestBody Map map) {
        String ip = (String) map.get("ip");
        String userName = (String) map.get("userName");
        String password = DesUtil.decode((String) map.get("password")); // 密码要解密
        Integer port = 22;
        String fileName = (String) map.get("fileName");
        SshUtil sshUtil = new SshUtil();
        boolean login = sshUtil.login(ip, port, userName, password);
        if (!login) {
            List<String> objects = new ArrayList<String>();
            objects.add("暂无匹配到可替换文件");
            return objects;
        }

        try {
            String realPath =  sshUtil.getRealWorkPath();
            realPath = realPath.replaceAll("\r|\n", "");
            String shell = "cd " + realPath + "; find " + realPath +"/ -name " + fileName;
            log.info("--find File command is--:" + shell);
            StringBuilder exec = sshUtil.exec(shell, login);
            List<String> strs = StringUtils.stringToList(exec.toString(), "\r|\n");
            sshUtil.logout();
            return strs;
        } catch (Exception e) {
            List<String> objects = new ArrayList<String>();
            objects.add("暂无匹配路径");
            return objects;
        }

    }

    /**
     * 塞包
     * @return
     */
    @PostMapping(path = "/execReplaceClass")
    public RespBean execReplaceClass(@RequestBody Map map) {

        // jef hotpath jar_path class_path
        String hostName = (String) map.get("hostName");
        String ip = (String) map.get("ip");
        String userName = (String) map.get("userName");
        String password = DesUtil.decode((String) map.get("password")); // 密码要解密
        String pid = (String) map.get("pid");
        Integer pidType = (Integer) map.get("pidType");
        Integer port = 22;
        String fileName = (String) map.get("fileName");
        String jarPath = (String) map.get("jarPath");

        SshUtil sshUtil = new SshUtil();
        boolean login = sshUtil.login(ip, port, userName, password);
        if (!login) {
            return RespBean.error("登录主机失败，请检查参数是否正确");
        }

        try {
            String realPath = sshUtil.getRealWorkPath(workpath);
            realPath = realPath.replaceAll("\r|\n", "");
            String shell = "cd " + realPath + "; jef hotpath " + jarPath + " " + "./" + fileName;
            log.info("--replace class command is--:" + shell);
            sshUtil.exec(shell, login);
            sshUtil.logout();
        } catch (Exception e) {
            e.printStackTrace();
            return RespBean.error("塞包失败，请确认jar包路径");
        }

        return RespBean.ok("塞包成功");
    }

    /**
     * 自动编译
     * @param map
     * @return
     */
    @PostMapping(path = "/compilation")
    public RespBean compilation(@RequestBody Map map) {

        String ip = (String) map.get("ip");
        String userName = (String) map.get("userName");
        String password = DesUtil.decode((String) map.get("password")); // 密码要解密
        Integer port = 22;
        String fileName = (String) map.get("fileName");
        Integer pidType = (Integer) map.get("pidType");
        String pid = (String) map.get("pid");
        SshUtil sshUtil = new SshUtil();
        boolean login = sshUtil.login(ip, port, userName, password);
        if (!login) {
            return RespBean.error("登录主机失败，请检查参数是否正确");
        }

        try {
            String symbol = "javac";
            if ("1".equals(pidType) || pidType == 1) {
                // 如果是1则是账管进程，
                 symbol = symbol + pid;
            } else {
                symbol = symbol + "other";
            }
            String realPath =  sshUtil.getRealWorkPath(workpath);
            realPath = realPath.replaceAll("\r|\n", "");
            //String shell = "cd " + realPath + "; " + "jef " + symbol + " " + fileName;
            String shell = "jef " + symbol + " " + realPath + "/" + fileName;

            log.info("--动态编译命令--:" + shell);
            StringBuilder stringBuilder = sshUtil.exec(shell);
            log.info("--动态编译执行结果--" + stringBuilder.toString());

            // 目的是为了让前端提示展示不同的风格
            String result = stringBuilder.toString();
            result = result.replaceAll("\r|\n", "");
            if (result.equals("") || result.equals("compilation success!")) {
                return RespBean.ok("compilation success!");
            } else {
                return RespBean.error(stringBuilder.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return RespBean.error("编译失败，请检查文件");
        } finally {
            sshUtil.logout();
        }



    }


}
